﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace FunCode
{
    public class DllFileModel
    {
        /// <summary>
        /// 文件名，包含后缀
        /// </summary>
        public string fileName { get; set; }
        /// <summary>
        /// 文件名，无后缀
        /// </summary>
        public string Name
        {
            get { return fileName.Remove(fileName.LastIndexOf('.')); }
        }
        /// <summary>
        /// 该dll下包含的实体集，以;号隔开
        /// </summary>
        public string ObjectContextStrings { get; set; }
        /// <summary>
        /// 该文件是否包含实体集
        /// </summary>
        public bool havaEFObjectContext { get; set; }
    }
    public class EFDriver
    {
        /// <summary>
        /// 获取一个文件夹下所以dll文件，并得到dll文件内包含EF的实体集
        /// </summary>
        /// <param name="di">目录</param>
        /// <returns></returns>
        public static List<DllFileModel> GetDllFileModels(DirectoryInfo di)
        {
            #region 使用反射判断dll里面是否有Entity
            List<DllFileModel> dllfiles = new List<DllFileModel>();            
            foreach (FileInfo fi in di.GetFiles("*.dll"))
            {
                List<string> entityNames = GetEntityName(fi.Name.Remove(fi.Name.LastIndexOf('.')));
                string Names = "";
                if (entityNames.Count > 0)
                {
                    Names = entityNames.Aggregate(Names, (current, name) => current + (name + ";"));
                }
                DllFileModel dllFileModle = new DllFileModel
                {
                    fileName = fi.Name,
                    havaEFObjectContext = entityNames.Count > 0,
                    ObjectContextStrings = Names
                };
                dllfiles.Add(dllFileModle);
            }
            return dllfiles;

            #endregion
        }
        /// <summary>
        /// 获取一个文件夹下所以dll文件，并得到dll文件内包含EF的实体集
        /// </summary>
        /// <param name="DirectoryFullName">目录的全路径</param>
        /// <returns></returns>
        public static List<DllFileModel> GetDllFileModels(String DirectoryFullName)
        {
            DirectoryInfo di = new DirectoryInfo(DirectoryFullName);
            return GetDllFileModels(di);
        }
        /// <summary>
        /// 获取DLL中的Entity，不存在返回空List
        /// </summary>
        /// <param name="efNamespace">EF所在命名空间</param>
        /// <returns></returns>
        public static List<string> GetEntityName(String efNamespace)
        {
            List<string> ObjectContexts = new List<string>();
            //try
            {
                var types = Assembly.Load(efNamespace).GetTypes();
                ObjectContexts.AddRange(from type in types
                                        where type.BaseType != null
                                        where type.BaseType.Name.Equals("ObjectContext")
                                        select type.Name);
            }
            //catch
            {
            }
            return ObjectContexts;
        }
        /// <summary>
        /// 获取实体集中所有的表名(未实现)
        /// </summary>
        /// <returns></returns>
        private static List<string> GetTables(String EntityName,String eFNamespace)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            return (from type in types
                    where type.BaseType != null
                    where type.BaseType.Name.Equals("EntityObject")
                    select type.Name).ToList();
        }
        /// <summary>
        /// 得到该命名空间下所有的表名
        /// </summary>
        /// <returns></returns>
        public static List<string> GetTables(String eFNamespace)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            return (from type in types
                    where type.BaseType != null
                    where type.BaseType.Name.Equals("EntityObject")
                    select type.Name).ToList();
        }
        public static List<string> GetPropertiesName(String eFNamespace, string tableName)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            Type table;
            try
            {
                table = types.Single(t => t.Name == tableName);
            }
            catch
            {
                return new List<string>();
            }
            return table.GetProperties().Select(Propertie => Propertie.Name).ToList();
        }
        /// <summary>
        /// 获取表中所有的字段，此处是EF从数据库映射出来的Csharp类型字段
        /// </summary>
        /// <param name="eFNamespace"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetProperties(String eFNamespace, string tableName)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            Type table;
            try
            {
                table = types.Single(t => t.Name == tableName);
            }
            catch
            {
                return new List<PropertyInfo>();
            }
            return table.GetProperties().ToList();
        }

        /// <summary>
        /// 获取表中所有的字段，此处是EF从数据库映射出来的Csharp类型字段
        /// </summary>
        /// <param name="eFNamespace"></param>
        /// <param name="tableName"></param>
        /// <param name="noCovered"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetProperties(String eFNamespace, string tableName, string[] noCovered)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            Type table;
            try
            {
                table = types.Single(t => t.Name == tableName);
            }
            catch
            {
                return new List<PropertyInfo>();
            }
            return table.GetProperties().Where(m => !noCovered.Contains(m.Name)).ToList();
        }
        /// <summary>
        /// 根据实体集，获取表中所有的字段，此处是EF从数据库映射出来的Csharp类型字段(未实现)
        /// </summary>
        /// <param name="EntityName"></param>
        /// <param name="eFNamespace"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        private static List<PropertyInfo> GetProperties(String EntityName, String eFNamespace, string tableName)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            Type table;
            try
            {
                table = types.Single(t => t.Name == tableName);
            }
            catch
            {
                return new List<PropertyInfo>();
            }
            return table.GetProperties().ToList();
        }
        /// <summary>
        /// 测试反射的方法，可以看看
        /// </summary>
        private void Loaded(String eFNamespace)
        {
            var types = Assembly.Load(eFNamespace).GetTypes();
            foreach (Type type in types)
            {
                print("类型", type.Name);
                if (type.BaseType.Name.Equals("ObjectContext") || type.BaseType.Name.Equals("EntityObject"))
                {
                    var members = type.GetMethods();
                    foreach (var member in members)
                    {
                        print("方法", member.Name);
                    }
                    var Properties = type.GetProperties();
                    foreach (var Propertie in Properties)
                    {
                        print("字段", Propertie.Name);
                        print("类型", Propertie.PropertyType.Name);
                    }
                }
            }
        }
        void print(string Strtype, string s)
        {
            Console.WriteLine(Strtype + "：" + s);
        }
    }

}
